﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace GJLib
{
    public class PillarGj
    {
        [JsonIgnore]
        protected String _gj = "";
        [JsonIgnore]
        public String 干
        {
            get { return _gj.Substring(0, 1); }
            set
            {
                if (String.IsNullOrEmpty(_gj))
                {
                    _gj = value+"_"  ;
                }
                else
                    _gj = value+ _gj.Substring(1, 1);
            }
        }
        [JsonIgnore]
        public String 支
        {
            get {
                if (_gj == null)
                    return null;
                return _gj.Substring(1, 1); 
            }
            set
            {
                if (String.IsNullOrEmpty(_gj))
                {
                    _gj = "_"+value ;
                }
                else
                    _gj = _gj.Substring(0, 1)+value;
            }
        }
        public String 干支
        {
            get { return _gj; }
            set { _gj = value; }
        }
        public PillarGj()
        {
            _gj = null;
        }
        public  PillarGj(String gj)
        {
            _gj = gj;
        }
    }
    public class Pillar4
    {
        [JsonIgnore]
        public DateTime datetime;
        public PillarGj yearGj;
        public PillarGj monthGj;
        public PillarGj dayGj;
        public PillarGj hourGj;
        public Pillar4()
        {
            yearGj = new PillarGj();
            monthGj = new PillarGj();
            dayGj = new PillarGj();
            hourGj = new PillarGj();
        }
        public Pillar4 clone()
        {
            Pillar4 r = new Pillar4();
            r.datetime = this.datetime;
            r.yearGj = new PillarGj(this.yearGj.干支);
            r.monthGj = new PillarGj(this.monthGj.干支);
            r.dayGj = new PillarGj(this.dayGj.干支);
            r.hourGj = new PillarGj(this.hourGj.干支);
            return r;
        }
        public void setGj(List<String> param)
        {
            yearGj = new PillarGj(param[0]);
            monthGj = new PillarGj(param[1]);
            dayGj = new PillarGj(param[2]);
            hourGj = new PillarGj(param[3]);
        }
    }
    public class YearDest
    {
        public int year { get; set; }
        public int age { get; set; }
        public String bigDest { get; set; }
        public String yearStar { get; set; }
        public String smallDest { get; set; }
    }
    public class BigDestRange
    {
        public DateTime startDate { get; set; }
        public int startAge { get; set; }
        public int endAge { get; set; }
        public String bigDest { get; set; }
    }
    public class GanJiHelper
    {

        public GanJiHelper()
        {
            
        }
     
        protected String next60GJ(String gj)
        {
            String gan = gj.Substring(0, 1);
            String ji = gj.Substring(1, 1);
            gan = GJR.nextGan(gan);
            ji = GJR.nextJi(ji);
            return gan + ji;
        }
        protected String prev60GJ(String gj)
        {
            String gan = gj.Substring(0, 1);
            String ji = gj.Substring(1, 1);
            gan =GJR.prevGan(gan);
            ji = GJR.prevJi(ji);
            return gan + ji;
        }
        protected bool getGanInYan(String gan)
        {
            int id = getGanId(gan);
            id = id % 2;
            if (id != 0)
                return true;
            return false;
        }
        protected List<String> pickNextGj(String gj, int count,bool plus)
        {
            List<String> result = new List<String>();
            for (int i = 0; i < count; i++)
            {
                if (plus)
                    gj = next60GJ(gj);
                else
                    gj = prev60GJ(gj);
                result.Add(gj);
            }    
            return result;
        }
        
        protected TimeSpan getToNextTimeSpan(TimeSpan jachiT,TimeSpan duration)
        {
            double tenyearsec = (3652.4219) * 24 * 60 * 60;
            double jachiSec = jachiT.TotalSeconds;
            double rate = tenyearsec / jachiSec;            
            TimeSpan r = new TimeSpan((long)(duration.Ticks * rate));
            return r;
        }
        public List<String> get4Pillar(DateTime dt, String HrJi)
        {
            List<String> gj=get4Pillar(dt);
            String dgan=gj[2].Substring(0, 1);
            int gaiod = GJR.ganId(dgan)-1;
            int jiid =GJR.JiId(HrJi)-1;
            int id = (gaiod * 12 + jiid) % 10+1;
            String hrgan =GJR.Id2Gan(id);
            gj[3]= hrgan + HrJi;
            return gj;
        }
        public static List<String> get4Pillar(DateTime dt)
        {
            Dictionary<String, Object> dayData = prepareEightWordGJ(dt);
            List<String> gj = (List<String>)dayData["gj"];
            return gj;
        }
        public Dictionary<String, Object> CalEightWordBasic(DateTime dt, bool male, EightWordConfig config)
        {
            Dictionary<String, Object> dayData = prepareEightWordGJ(dt);
            List<String> gj = (List<String>)dayData["gj"];
            //順逆..
            bool isYan = calIsYan(male, gj);
            //起大運的年份
            DateTime startDestYear = calStartDestYear(dt, isYan);
            //起大運的虛歲
            int startAge = calStartAge(dt, startDestYear);
            //大運            
            List<BigDestRange> bigDestRange=prepareBigDestRange(startAge,startDestYear, gj[1], isYan);
            //年運
            List<YearDest> yearDest=prepareYearDest(dt, gj, isYan, startAge);
            Dictionary<String, Object> result = new Dictionary<string, object>();
            result.Add("時間", dt);
            result.Add("daydata", dayData);
            result.Add("年柱", gj[0]);
            result.Add("月柱", gj[1]);
            result.Add("日柱", gj[2]);
            result.Add("時柱", gj[3]);
            result.Add("起運歲", startAge);
            result.Add("起運", startDestYear);
            result.Add("大運", bigDestRange);
            result.Add("年運", yearDest);
            String c=JsonConvert.SerializeObject(result,Formatting.Indented);
            File.WriteAllText(@"d:\1.json", c, Encoding.UTF8);
            return result;
        }

        private int calStartAge(DateTime dt, DateTime startDestYear)
        {
            DateTime yearStart = JachiHelper.getYearStartDate(startDestYear.Year);
            int m = startDestYear.Month;
            int startAge = yearStart.Year - dt.Year;

            if (startDestYear.CompareTo(yearStart) > 0)
                startAge++;
            return startAge;
        }

        private bool calIsYan(bool male, List<String> gj)
        {
            String yearGan = gj[0].Substring(0, 1);
            bool isYan = getGanInYan(yearGan);
            if (male == false)
                isYan = !isYan;
            return isYan;
        }

        private DateTime calStartDestYear(DateTime dt, bool isYan)
        {
            DateTime startDestYear;
            TimeSpan t1, t2;
            JachiHelper.calTimeSpantoJachi(dt, out t1, out t2);
            TimeSpan t3 = t1.Add(t2);
            TimeSpan toNext;
            if (isYan)
                toNext = t2;
            else
                toNext = t1;

            toNext = getToNextTimeSpan(t3, toNext);
            startDestYear = dt.Add(toNext);
            return startDestYear;
        }

        List<BigDestRange> prepareBigDestRange(int startAge,DateTime startDate, String mgj, bool isYan)
        {
            List<String> gjs = pickNextGj(mgj, 10, isYan);
            List<BigDestRange> result = new List<BigDestRange>();
            int age=startAge;
            TimeSpan ts = new TimeSpan(3652, 10, 7, 30, 360); //十年=3652天,10小時 7分,30秒,
            foreach (String d in gjs)
            {
                BigDestRange r = new BigDestRange();
                r.bigDest = d;
                r.startAge = age;
                r.endAge = age + 9;
                r.startDate = startDate;
                startDate=startDate.Add(ts);
                age += 10;
                result.Add(r);
            }
            return result;
        }

        private List<YearDest> prepareYearDest(DateTime dt, List<String> gj, bool isYan, int startAge)
        {
            String mgj = gj[1];
            List<String> bigDestGJ = pickNextGj(mgj, 10, isYan);

            String dgj = gj[2];
            List<String> smallDestGJ = pickNextGj(dgj, 100, isYan);//小運          

            String ygj = gj[0];
            List<String> yearGj = pickNextGj(ygj, 100, true);
            yearGj.Insert(0, ygj);            //----------

            List<YearDest> yearDests = new List<YearDest>();
            for (int i = 0; i < 100; i++)
            {
                YearDest yd = new YearDest();
                yd.year = dt.Year + i ;
                yd.age = i+1;
                yd.yearStar = yearGj[i];
                yd.smallDest = smallDestGJ[i];
                yd.bigDest = ygj;
                int k = (i +1)- startAge;
                if (k >= 0)
                {
                    k /= 10;
                    yd.bigDest = bigDestGJ[k];
                }
                yearDests.Add(yd);
            }
            return yearDests;
        }




        private static Dictionary<String, Object> prepareEightWordGJ(DateTime dt)
        {
            Dictionary<String, Object> dayData = getDayGanJi(dt.Year, dt.Month, dt.Day);
            List<String> gj = (List<String>)dayData["gj"];
            int sz=gj.Count;
            for(int i=0;i<sz;i++)
            {
                gj[i]=GJR.checkGJ(gj[i]);
            }
            String dayGJ = gj[2];
            String hrGj = calculateHourGj(dayGJ, dt.Hour);
            gj.Add(hrGj);
            return dayData;
        }

        private static String[] jis = { "亥", "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" };
        private static String[] gans = { "癸", "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" };

        private static String IdtoGan(int id)
        {
            id = id % 10 + 1;
            return gans[id];
        }

        private static int getGanId(String gan)
        {
            for (int i = 1; i <= 10; i++)
            {
                if (gans[i].Equals(gan))
                    return i;
            }
            return 0;
        }
        private static String getHrJi(int hr)
        {
            int pos = ((hr + 1) / 2 % 12) + 1;
            return jis[pos];
        }

        private static String calculateHourGj(string dayGJ, int hr)
        {
            dayGJ = dayGJ.Trim();
            String w1 = dayGJ.Substring(0, 1);
            int id = getGanId(w1);
            String ji = getHrJi(hr);
            id = ((id - 1) * 12 + (hr + 1) / 2);
            String gan = IdtoGan(id);
            String result = gan + ji;
            return result;
        }


        public static List<T> convertToList<T>(JToken jt)
        {
            List<T> result = new List<T>();
            var items = jt.Values<T>();
            foreach (var item in items)
            {
                result.Add((T)item);
            }
            return result;
        }
        private static Dictionary<String, object> getDayGanJi(int p_1, int p_2, int p_3)
        {
            Dictionary<String, object> result = new Dictionary<string, object>();
            JObject daydata = fetchDaydata(p_1, p_2, p_3);
            List<String> gj = convertToList<String>(daydata["gj"]);
            List<String> suitable = convertToList<String>(daydata["suitable"]);
            List<String> prohibit = convertToList<String>(daydata["prohibit"]);
            List<int> lunar = convertToList<int>(daydata["lunar"]);
            //處理 gj的錯誤問題
            if (gj[0][1] == '已')
            {
                gj[0] = gj[0].Substring(0, 1) + "巳";
            }
            if (gj[1][1] == '已')
            {
                gj[1] = gj[1].Substring(0, 1) + "巳";
            }
            if (gj[2][1] == '已')
            {
                gj[2] = gj[2].Substring(0, 1) + "巳";
            }    


            if (daydata["intercalary"] != null)
            {
                result.Add("intercalary", true);
            }
            else
                result.Add("intercalary", false);

            result.Add("gj", gj);
            result.Add("suitable", suitable);
            result.Add("prohibit", prohibit);
            result.Add("lunar", lunar);
            return result;
        }

        public static JObject fetchDaydata(int p_1, int p_2, int p_3)
        {
            String p = getDayJsonPath();
            String fileName = p + "\\" + p_1 + "-" + p_2 + ".json";
            if (File.Exists(fileName) == false)
                return null;
            String content = File.ReadAllText(fileName);
            Dictionary<String, JObject> datas = JsonConvert.DeserializeObject<Dictionary<String, JObject>>(content);
            String key = String.Format("{0}/{1}/{2}", p_1, p_2, p_3);

            JObject jo = datas[key];
            datas.Clear();
            content = "";
            return jo;
        }

        private static string getDayJsonPath()
        {
            const String p = @"D:\project\五術\data\month";
            return p;
        }
        /***********************************************************************
         * 
         * **********************************************************************/
        public  static string[] getJis()
        {
            return jis;
        }

        
    }
}
